package repository

import (
	"context"
	"errors"
	v1 "gin-vben-admin/api/v1"
	"gin-vben-admin/internal/model"
	"gorm.io/gorm"
)

type SysUserRepository interface {
	PageList(ctx context.Context, req *v1.SysUserListReq, preloads ...string) (total int64, list []*model.SysUser, err error)
	Create(ctx context.Context, user *model.SysUser) error
	Update(ctx context.Context, user *model.SysUser, fields ...string) error
	Delete(ctx context.Context, uid int64) error
	GetByID(ctx context.Context, uid int64) (*model.SysUser, error)
	GetByEmailOrUsername(ctx context.Context, email string, username string) (*model.SysUser, error)
	GetByUsername(ctx context.Context, username string) (user *model.SysUser, err error)
	GetByPhone(ctx context.Context, phone string, excludeId ...int64) (user *model.SysUser, err error)
	GetByEmail(ctx context.Context, email string, excludeId ...int64) (user *model.SysUser, err error)
}

func NewSysUserRepository(r *Repository) SysUserRepository {
	return &sysUserRepository{
		Repository: r,
	}
}

type sysUserRepository struct {
	*Repository
}

func (r *sysUserRepository) PageList(ctx context.Context, req *v1.SysUserListReq, preloads ...string) (total int64, list []*model.SysUser, err error) {
	list = make([]*model.SysUser, 0)
	_db := r.DB(ctx).Model(model.SysUser{})
	if req.Kw != "" {
		kw := "%" + req.Kw + "%"
		_db = _db.Scopes(func(db *gorm.DB) *gorm.DB {
			return db.Where("username like ? or nick_name like ? or email like ?", kw, kw, kw)
		})
	}
	if req.Status != 0 {
		_db = _db.Where("status = ?", req.Status)
	}
	if req.DeptId != 0 {
		_db = _db.Where("dept_id = ?", req.DeptId)
	}
	if req.RoleId != 0 {
		_db = _db.Where("status = ?", req.RoleId)
	}
	err = _db.Count(&total).Error
	if err != nil || total == 0 {
		return
	}
	_db = _db.Scopes(req.PageQuery())
	for i := range preloads {
		_db = _db.Preload(preloads[i])
	}
	err = _db.Find(&list).Error
	return
}

func (r *sysUserRepository) Create(ctx context.Context, user *model.SysUser) error {
	if err := r.DB(ctx).Create(user).Error; err != nil {
		return err
	}
	return nil
}

func (r *sysUserRepository) Update(ctx context.Context, user *model.SysUser, fields ...string) error {
	_db := r.DB(ctx)
	if len(fields) > 0 {
		_db = _db.Select(fields)
	}
	return _db.Where("uid = ?", user.UID).Updates(user).Error
}

func (r *sysUserRepository) Delete(ctx context.Context, uid int64) error {
	return r.DB(ctx).Delete(&model.SysUser{UID: uid}).Error
}

func (r *sysUserRepository) GetByID(ctx context.Context, userId int64) (m *model.SysUser, err error) {
	err = r.DB(ctx).Where("uid = ?", userId).First(&m).Error
	return
}

func (r *sysUserRepository) GetByEmailOrUsername(ctx context.Context, email, username string) (*model.SysUser, error) {
	var user model.SysUser
	var err error
	if email != "" && username != "" {
		err = r.DB(ctx).Where("email = ? or username", email, username).First(&user).Error
	} else {
		if email != "" {
			err = r.DB(ctx).Where("email = ?", email).First(&user).Error
		} else if username != "" {
			err = r.DB(ctx).Where("username = ?", username).First(&user).Error
		} else {
			return nil, nil
		}
	}

	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, nil
		}
		return nil, err
	}
	return &user, nil
}

func (r *sysUserRepository) GetByUsername(ctx context.Context, username string) (user *model.SysUser, err error) {
	err = r.DB(ctx).Where("username = ?", username).First(&user).Error
	if errors.Is(err, gorm.ErrRecordNotFound) {
		err = nil
	}
	return
}

func (r *sysUserRepository) GetByPhone(ctx context.Context, phone string, excludeId ...int64) (user *model.SysUser, err error) {
	if len(excludeId) > 0 {
		err = r.DB(ctx).Where("phone = ? and uid not in ?", phone, excludeId).First(&user).Error
	} else {
		err = r.DB(ctx).Where("phone = ?", phone).First(&user).Error
	}
	if errors.Is(err, gorm.ErrRecordNotFound) {
		err = nil
	}
	return
}

func (r *sysUserRepository) GetByEmail(ctx context.Context, email string, excludeId ...int64) (user *model.SysUser, err error) {
	if len(excludeId) > 0 {
		err = r.DB(ctx).Where("email = ? and uid not in ?", email, excludeId).First(&user).Error
	} else {
		err = r.DB(ctx).Where("email = ?", email).First(&user).Error
	}
	if errors.Is(err, gorm.ErrRecordNotFound) {
		err = nil
	}
	return
}
